{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<font color=\"red\">注</font>: 使用 tensorboard 可视化需要安装 tensorflow (TensorBoard依赖于tensorflow库，可以任意安装tensorflow的gpu/cpu版本)\n",
    "\n",
    "```shell\n",
    "pip install tensorflow-cpu\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-04-30T03:08:26.466719400Z",
     "start_time": "2024-04-30T03:08:17.277867200Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-22T09:36:58.697307Z",
     "iopub.status.busy": "2025-01-22T09:36:58.697099Z",
     "iopub.status.idle": "2025-01-22T09:37:00.820992Z",
     "shell.execute_reply": "2025-01-22T09:37:00.820475Z",
     "shell.execute_reply.started": "2025-01-22T09:36:58.697284Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/usr/local/lib/python3.10/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
      "  from .autonotebook import tqdm as notebook_tqdm\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "sys.version_info(major=3, minor=10, micro=14, releaselevel='final', serial=0)\n",
      "matplotlib 3.10.0\n",
      "numpy 1.26.4\n",
      "pandas 2.2.3\n",
      "sklearn 1.6.0\n",
      "torch 2.5.1+cu124\n",
      "cuda:0\n"
     ]
    }
   ],
   "source": [
    "import matplotlib as mpl\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "import numpy as np\n",
    "import sklearn\n",
    "import pandas as pd\n",
    "import os\n",
    "import sys\n",
    "import time\n",
    "from tqdm.auto import tqdm\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "\n",
    "print(sys.version_info)\n",
    "for module in mpl, np, pd, sklearn, torch:\n",
    "    print(module.__name__, module.__version__)\n",
    "    \n",
    "device = torch.device(\"cuda:0\") if torch.cuda.is_available() else torch.device(\"cpu\")\n",
    "print(device)\n",
    "\n",
    "seed = 42\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 数据准备\n",
    "\n",
    "https://www.kaggle.com/competitions/cifar-10/data\n",
    "\n",
    "```shell\n",
    "$ tree -L 1 cifar-10                                    \n",
    "cifar-10\n",
    "├── sampleSubmission.csv\n",
    "├── test\n",
    "├── train\n",
    "└── trainLabels.csv\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-04-30T03:09:27.792078300Z",
     "start_time": "2024-04-30T03:09:23.644044900Z"
    },
    "ExecutionIndicator": {
     "show": true
    },
    "execution": {
     "iopub.execute_input": "2025-01-22T09:37:00.822668Z",
     "iopub.status.busy": "2025-01-22T09:37:00.822144Z",
     "iopub.status.idle": "2025-01-22T09:37:03.066183Z",
     "shell.execute_reply": "2025-01-22T09:37:03.065622Z",
     "shell.execute_reply.started": "2025-01-22T09:37:00.822646Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[(PosixPath('competitions/cifar-10/train/1.png'), 'frog'),\n",
      " (PosixPath('competitions/cifar-10/train/2.png'), 'truck'),\n",
      " (PosixPath('competitions/cifar-10/train/3.png'), 'truck'),\n",
      " (PosixPath('competitions/cifar-10/train/4.png'), 'deer'),\n",
      " (PosixPath('competitions/cifar-10/train/5.png'), 'automobile')]\n",
      "[(PosixPath('competitions/cifar-10/test/1.png'), 'cat'),\n",
      " (PosixPath('competitions/cifar-10/test/2.png'), 'cat'),\n",
      " (PosixPath('competitions/cifar-10/test/3.png'), 'cat'),\n",
      " (PosixPath('competitions/cifar-10/test/4.png'), 'cat'),\n",
      " (PosixPath('competitions/cifar-10/test/5.png'), 'cat')]\n",
      "50000 300000\n"
     ]
    }
   ],
   "source": [
    "from pathlib import Path\n",
    "\n",
    "DATA_DIR = Path(\".\")\n",
    "DATA_DIR1 =Path(\"competitions/cifar-10/\")\n",
    "train_lables_file = DATA_DIR / \"trainLabels.csv\"\n",
    "test_csv_file = DATA_DIR / \"sampleSubmission.csv\" #测试集模板csv文件\n",
    "train_folder = DATA_DIR1 / \"train\"\n",
    "test_folder = DATA_DIR1 / \"test\"\n",
    "\n",
    "#所有的类别\n",
    "class_names = [\n",
    "    'airplane',\n",
    "    'automobile',\n",
    "    'bird',\n",
    "    'cat',\n",
    "    'deer',\n",
    "    'dog',\n",
    "    'frog',\n",
    "    'horse',\n",
    "    'ship',\n",
    "    'truck',\n",
    "]\n",
    "\n",
    "def parse_csv_file(filepath, folder):\n",
    "    \"\"\"Parses csv files into (filename(path), label) format\"\"\"\n",
    "    results = []\n",
    "    #读取所有行\n",
    "    with open(filepath, 'r') as f:\n",
    "#         lines = f.readlines()  为什么加[1:]，可以试这个\n",
    "        #第一行不需要，因为第一行是标签\n",
    "        lines = f.readlines()[1:] \n",
    "    for line in lines:#依次去取每一行\n",
    "        image_id, label_str = line.strip('\\n').split(',')\n",
    "        image_full_path = folder / f\"{image_id}.png\"\n",
    "        results.append((image_full_path, label_str)) #得到对应图片的路径和分类\n",
    "    return results\n",
    "\n",
    "#解析对应的文件夹\n",
    "train_labels_info = parse_csv_file(train_lables_file, train_folder)\n",
    "test_csv_info = parse_csv_file(test_csv_file, test_folder)\n",
    "#打印\n",
    "import pprint\n",
    "pprint.pprint(train_labels_info[0:5])\n",
    "pprint.pprint(test_csv_info[0:5])\n",
    "print(len(train_labels_info), len(test_csv_info))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-04-30T03:09:30.583944400Z",
     "start_time": "2024-04-30T03:09:30.436028300Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-22T09:37:03.067066Z",
     "iopub.status.busy": "2025-01-22T09:37:03.066848Z",
     "iopub.status.idle": "2025-01-22T09:37:03.123260Z",
     "shell.execute_reply": "2025-01-22T09:37:03.122714Z",
     "shell.execute_reply.started": "2025-01-22T09:37:03.067045Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "                            filepath       class\n",
      "0  competitions/cifar-10/train/1.png        frog\n",
      "1  competitions/cifar-10/train/2.png       truck\n",
      "2  competitions/cifar-10/train/3.png       truck\n",
      "3  competitions/cifar-10/train/4.png        deer\n",
      "4  competitions/cifar-10/train/5.png  automobile\n",
      "                                filepath       class\n",
      "0  competitions/cifar-10/train/45001.png       horse\n",
      "1  competitions/cifar-10/train/45002.png  automobile\n",
      "2  competitions/cifar-10/train/45003.png        deer\n",
      "3  competitions/cifar-10/train/45004.png  automobile\n",
      "4  competitions/cifar-10/train/45005.png    airplane\n",
      "                           filepath class\n",
      "0  competitions/cifar-10/test/1.png   cat\n",
      "1  competitions/cifar-10/test/2.png   cat\n",
      "2  competitions/cifar-10/test/3.png   cat\n",
      "3  competitions/cifar-10/test/4.png   cat\n",
      "4  competitions/cifar-10/test/5.png   cat\n"
     ]
    }
   ],
   "source": [
    "# train_df = pd.DataFrame(train_labels_info)\n",
    "train_df = pd.DataFrame(train_labels_info[0:45000])\n",
    "valid_df = pd.DataFrame(train_labels_info[45000:])\n",
    "test_df = pd.DataFrame(test_csv_info)\n",
    "\n",
    "train_df.columns = ['filepath', 'class']\n",
    "valid_df.columns = ['filepath', 'class']\n",
    "test_df.columns = ['filepath', 'class']\n",
    "\n",
    "print(train_df.head())\n",
    "print(valid_df.head())\n",
    "print(test_df.head())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-04-30T03:09:40.361166200Z",
     "start_time": "2024-04-30T03:09:38.275234700Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-22T09:37:03.124043Z",
     "iopub.status.busy": "2025-01-22T09:37:03.123847Z",
     "iopub.status.idle": "2025-01-22T09:37:03.934009Z",
     "shell.execute_reply": "2025-01-22T09:37:03.933439Z",
     "shell.execute_reply.started": "2025-01-22T09:37:03.124023Z"
    }
   },
   "outputs": [],
   "source": [
    "from PIL import Image\n",
    "from torch.utils.data import Dataset, DataLoader\n",
    "from torchvision import transforms\n",
    "\n",
    "class Cifar10Dataset(Dataset):\n",
    "    df_map = {\n",
    "        \"train\": train_df,\n",
    "        \"eval\": valid_df,\n",
    "        \"test\": test_df\n",
    "    }\n",
    "    label_to_idx = {label: idx for idx, label in enumerate(class_names)}\n",
    "    idx_to_label = {idx: label for idx, label in enumerate(class_names)}\n",
    "    def __init__(self, mode, transform=None):\n",
    "        self.df = self.df_map.get(mode, None)\n",
    "        if self.df is None:\n",
    "            raise ValueError(\"mode should be one of train, val, test, but got {}\".format(mode))\n",
    "\n",
    "        self.transform = transform\n",
    "        \n",
    "    def __getitem__(self, index):\n",
    "        img_path, label = self.df.iloc[index]\n",
    "        img = Image.open(img_path).convert('RGB')\n",
    "        # # img 转换为 channel first\n",
    "        # img = img.transpose((2, 0, 1))\n",
    "        # transform\n",
    "        img = self.transform(img)\n",
    "        # label 转换为 idx\n",
    "        label = self.label_to_idx[label]\n",
    "        return img, label\n",
    "    \n",
    "    def __len__(self):\n",
    "        return self.df.shape[0]\n",
    "    \n",
    "IMAGE_SIZE = 32\n",
    "mean, std = [0.4914, 0.4822, 0.4465], [0.247, 0.243, 0.261]\n",
    "\n",
    "transforms_train = transforms.Compose([\n",
    "        # resize\n",
    "        transforms.Resize((IMAGE_SIZE, IMAGE_SIZE)),\n",
    "        # random rotation 40\n",
    "        transforms.RandomRotation(40),\n",
    "        # horizaontal flip\n",
    "        transforms.RandomHorizontalFlip(),\n",
    "        transforms.ToTensor(),\n",
    "        transforms.Normalize(mean, std)\n",
    "    ])\n",
    "\n",
    "transforms_eval = transforms.Compose([\n",
    "        # resize\n",
    "        transforms.Resize((IMAGE_SIZE, IMAGE_SIZE)),\n",
    "        transforms.ToTensor(),\n",
    "        transforms.Normalize(mean, std)\n",
    "    ])\n",
    "\n",
    "train_ds = Cifar10Dataset(\"train\", transforms_train)\n",
    "eval_ds = Cifar10Dataset(\"eval\", transforms_eval) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-04-30T03:09:43.545874100Z",
     "start_time": "2024-04-30T03:09:43.519888900Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-22T09:37:03.934926Z",
     "iopub.status.busy": "2025-01-22T09:37:03.934624Z",
     "iopub.status.idle": "2025-01-22T09:37:03.938228Z",
     "shell.execute_reply": "2025-01-22T09:37:03.937661Z",
     "shell.execute_reply.started": "2025-01-22T09:37:03.934904Z"
    }
   },
   "outputs": [],
   "source": [
    "batch_size = 64\n",
    "train_dl = DataLoader(train_ds, batch_size=batch_size, shuffle=True, num_workers=4)   \n",
    "eval_dl = DataLoader(eval_ds, batch_size=batch_size, shuffle=False, num_workers=4)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-01-22T09:37:03.939004Z",
     "iopub.status.busy": "2025-01-22T09:37:03.938813Z",
     "iopub.status.idle": "2025-01-22T09:37:03.941520Z",
     "shell.execute_reply": "2025-01-22T09:37:03.941063Z",
     "shell.execute_reply.started": "2025-01-22T09:37:03.938985Z"
    }
   },
   "outputs": [],
   "source": [
    "# 遍历train_ds得到每张图片，计算每个通道的均值和方差\n",
    "# def cal_mean_std(ds):\n",
    "#     mean = 0.\n",
    "#     std = 0.\n",
    "#     for img, _ in ds:\n",
    "#         mean += img.mean(dim=(1, 2))\n",
    "#         std += img.std(dim=(1, 2))\n",
    "#     mean /= len(ds)\n",
    "#     std /= len(ds)\n",
    "#     return mean, std\n",
    "#\n",
    "# # 经过 normalize 后 均值为0，方差为1\n",
    "# print(cal_mean_std(train_ds))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 定义模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-04-30T03:33:59.691021200Z",
     "start_time": "2024-04-30T03:33:59.642042400Z"
    },
    "execution": {
     "iopub.execute_input": "2025-01-22T09:37:03.943430Z",
     "iopub.status.busy": "2025-01-22T09:37:03.943245Z",
     "iopub.status.idle": "2025-01-22T09:37:03.953778Z",
     "shell.execute_reply": "2025-01-22T09:37:03.953325Z",
     "shell.execute_reply.started": "2025-01-22T09:37:03.943411Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "             model.0.weight             paramerters num: 864\n",
      "              model.0.bias              paramerters num: 32\n",
      "             model.2.weight             paramerters num: 9216\n",
      "              model.2.bias              paramerters num: 32\n",
      "             model.5.weight             paramerters num: 9216\n",
      "              model.5.bias              paramerters num: 32\n",
      "             model.7.weight             paramerters num: 9216\n",
      "              model.7.bias              paramerters num: 32\n",
      "            model.10.weight             paramerters num: 9216\n",
      "             model.10.bias              paramerters num: 32\n",
      "            model.12.weight             paramerters num: 9216\n",
      "             model.12.bias              paramerters num: 32\n",
      "            model.16.weight             paramerters num: 5120\n",
      "             model.16.bias              paramerters num: 10\n"
     ]
    }
   ],
   "source": [
    "class VGG(nn.Module):\n",
    "    def __init__(self, num_classes):\n",
    "        super().__init__()\n",
    "        self.model = nn.Sequential(\n",
    "            nn.Conv2d(in_channels=3, out_channels=32, kernel_size=3, padding=\"same\"),\n",
    "            nn.ReLU(),\n",
    "            nn.Conv2d(in_channels=32, out_channels=32, kernel_size=3, padding=\"same\"),\n",
    "            nn.ReLU(),\n",
    "            nn.MaxPool2d(kernel_size=2),\n",
    "            nn.Conv2d(in_channels=32, out_channels=32, kernel_size=3, padding=\"same\"),\n",
    "            nn.ReLU(),\n",
    "            nn.Conv2d(in_channels=32, out_channels=32, kernel_size=3, padding=\"same\"),\n",
    "            nn.ReLU(),\n",
    "            nn.MaxPool2d(kernel_size=2),\n",
    "            nn.Conv2d(in_channels=32, out_channels=32, kernel_size=3, padding=\"same\"),\n",
    "            nn.ReLU(),\n",
    "            nn.Conv2d(in_channels=32, out_channels=32, kernel_size=3, padding=\"same\"),\n",
    "            nn.ReLU(),\n",
    "            nn.MaxPool2d(kernel_size=2),\n",
    "            nn.Flatten(),\n",
    "            nn.Linear(512, num_classes),\n",
    "        )\n",
    "        self.init_weights()\n",
    "        \n",
    "    def init_weights(self):\n",
    "        \"\"\"使用 xavier 均匀分布来初始化全连接层、卷积层的权重 W\"\"\"\n",
    "        for m in self.modules():\n",
    "            if isinstance(m, (nn.Linear, nn.Conv2d)): # 全连接层、卷积层\n",
    "                nn.init.kaiming_uniform_(m.weight, mode='fan_in', nonlinearity='relu') # 采用kaiming_uniform初始化权重, mode='fan_in'表示权重初始化为均匀分布，nonlinearity='relu'表示激活函数为relu\n",
    "                if m.bias is not None:\n",
    "                    nn.init.constant_(m.bias, 0.01)  # 偏置初始化为常数值，比如0.01\n",
    "        \n",
    "    def forward(self, x):\n",
    "        return self.model(x)\n",
    "        \n",
    "for key, value in VGG(len(class_names)).named_parameters():\n",
    "    print(f\"{key:^40}paramerters num: {np.prod(value.shape)}\")\n",
    "    \n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 训练\n",
    "\n",
    "pytorch的训练需要自行实现，包括\n",
    "1. 定义损失函数\n",
    "2. 定义优化器\n",
    "3. 定义训练步\n",
    "4. 训练"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-01-22T09:37:03.954444Z",
     "iopub.status.busy": "2025-01-22T09:37:03.954271Z",
     "iopub.status.idle": "2025-01-22T09:37:03.980824Z",
     "shell.execute_reply": "2025-01-22T09:37:03.980346Z",
     "shell.execute_reply.started": "2025-01-22T09:37:03.954425Z"
    }
   },
   "outputs": [],
   "source": [
    "from sklearn.metrics import accuracy_score\n",
    "\n",
    "@torch.no_grad()\n",
    "def evaluating(model, dataloader, loss_fct):\n",
    "    loss_list = []\n",
    "    pred_list = []\n",
    "    label_list = []\n",
    "    for datas, labels in dataloader:\n",
    "        datas = datas.to(device)\n",
    "        labels = labels.to(device)\n",
    "        # 前向计算\n",
    "        logits = model(datas)\n",
    "        loss = loss_fct(logits, labels)         # 验证集损失\n",
    "        loss_list.append(loss.item())\n",
    "        \n",
    "        preds = logits.argmax(axis=-1)    # 验证集预测\n",
    "        pred_list.extend(preds.cpu().numpy().tolist())\n",
    "        label_list.extend(labels.cpu().numpy().tolist())\n",
    "        \n",
    "    acc = accuracy_score(label_list, pred_list)\n",
    "    return np.mean(loss_list), acc\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### TensorBoard 可视化\n",
    "\n",
    "\n",
    "训练过程中可以使用如下命令启动tensorboard服务。\n",
    "\n",
    "```shell\n",
    "tensorboard \\\n",
    "    --logdir=runs \\     # log 存放路径\n",
    "    --host 0.0.0.0 \\    # ip\n",
    "    --port 8848         # 端口\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-01-22T09:37:03.981647Z",
     "iopub.status.busy": "2025-01-22T09:37:03.981383Z",
     "iopub.status.idle": "2025-01-22T09:37:04.040828Z",
     "shell.execute_reply": "2025-01-22T09:37:04.040292Z",
     "shell.execute_reply.started": "2025-01-22T09:37:03.981626Z"
    }
   },
   "outputs": [],
   "source": [
    "from torch.utils.tensorboard import SummaryWriter\n",
    "\n",
    "\n",
    "class TensorBoardCallback:\n",
    "    def __init__(self, log_dir, flush_secs=10):\n",
    "        \"\"\"\n",
    "        Args:\n",
    "            log_dir (str): dir to write log.\n",
    "            flush_secs (int, optional): write to dsk each flush_secs seconds. Defaults to 10.\n",
    "        \"\"\"\n",
    "        self.writer = SummaryWriter(log_dir=log_dir, flush_secs=flush_secs)\n",
    "\n",
    "    def draw_model(self, model, input_shape):\n",
    "        self.writer.add_graph(model, input_to_model=torch.randn(input_shape))\n",
    "        \n",
    "    def add_loss_scalars(self, step, loss, val_loss):\n",
    "        self.writer.add_scalars(\n",
    "            main_tag=\"training/loss\", \n",
    "            tag_scalar_dict={\"loss\": loss, \"val_loss\": val_loss},\n",
    "            global_step=step,\n",
    "            )\n",
    "        \n",
    "    def add_acc_scalars(self, step, acc, val_acc):\n",
    "        self.writer.add_scalars(\n",
    "            main_tag=\"training/accuracy\",\n",
    "            tag_scalar_dict={\"accuracy\": acc, \"val_accuracy\": val_acc},\n",
    "            global_step=step,\n",
    "        )\n",
    "        \n",
    "    def add_lr_scalars(self, step, learning_rate):\n",
    "        self.writer.add_scalars(\n",
    "            main_tag=\"training/learning_rate\",\n",
    "            tag_scalar_dict={\"learning_rate\": learning_rate},\n",
    "            global_step=step,\n",
    "            \n",
    "        )\n",
    "    \n",
    "    def __call__(self, step, **kwargs):\n",
    "        # add loss\n",
    "        loss = kwargs.pop(\"loss\", None)\n",
    "        val_loss = kwargs.pop(\"val_loss\", None)\n",
    "        if loss is not None and val_loss is not None:\n",
    "            self.add_loss_scalars(step, loss, val_loss)\n",
    "        # add acc\n",
    "        acc = kwargs.pop(\"acc\", None)\n",
    "        val_acc = kwargs.pop(\"val_acc\", None)\n",
    "        if acc is not None and val_acc is not None:\n",
    "            self.add_acc_scalars(step, acc, val_acc)\n",
    "        # add lr\n",
    "        learning_rate = kwargs.pop(\"lr\", None)\n",
    "        if learning_rate is not None:\n",
    "            self.add_lr_scalars(step, learning_rate)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Save Best\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-01-22T09:37:04.041733Z",
     "iopub.status.busy": "2025-01-22T09:37:04.041445Z",
     "iopub.status.idle": "2025-01-22T09:37:04.046930Z",
     "shell.execute_reply": "2025-01-22T09:37:04.046410Z",
     "shell.execute_reply.started": "2025-01-22T09:37:04.041712Z"
    }
   },
   "outputs": [],
   "source": [
    "class SaveCheckpointsCallback:\n",
    "    def __init__(self, save_dir, save_step=5000, save_best_only=True):\n",
    "        \"\"\"\n",
    "        Save checkpoints each save_epoch epoch. \n",
    "        We save checkpoint by epoch in this implementation.\n",
    "        Usually, training scripts with pytorch evaluating model and save checkpoint by step.\n",
    "\n",
    "        Args:\n",
    "            save_dir (str): dir to save checkpoint\n",
    "            save_epoch (int, optional): the frequency to save checkpoint. Defaults to 1.\n",
    "            save_best_only (bool, optional): If True, only save the best model or save each model at every epoch.\n",
    "        \"\"\"\n",
    "        self.save_dir = save_dir\n",
    "        self.save_step = save_step\n",
    "        self.save_best_only = save_best_only\n",
    "        self.best_metrics = -1\n",
    "        \n",
    "        # mkdir\n",
    "        if not os.path.exists(self.save_dir):\n",
    "            os.mkdir(self.save_dir)\n",
    "        \n",
    "    def __call__(self, step, state_dict, metric=None):\n",
    "        if step % self.save_step > 0:\n",
    "            return\n",
    "        \n",
    "        if self.save_best_only:\n",
    "            assert metric is not None\n",
    "            if metric >= self.best_metrics:\n",
    "                # save checkpoints\n",
    "                torch.save(state_dict, os.path.join(self.save_dir, \"best.ckpt\"))\n",
    "                # update best metrics\n",
    "                self.best_metrics = metric\n",
    "        else:\n",
    "            torch.save(state_dict, os.path.join(self.save_dir, f\"{step}.ckpt\"))\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Early Stop"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-01-22T09:37:04.048000Z",
     "iopub.status.busy": "2025-01-22T09:37:04.047624Z",
     "iopub.status.idle": "2025-01-22T09:37:04.051936Z",
     "shell.execute_reply": "2025-01-22T09:37:04.051474Z",
     "shell.execute_reply.started": "2025-01-22T09:37:04.047981Z"
    }
   },
   "outputs": [],
   "source": [
    "class EarlyStopCallback:\n",
    "    def __init__(self, patience=5, min_delta=0.01):\n",
    "        \"\"\"\n",
    "\n",
    "        Args:\n",
    "            patience (int, optional): Number of epochs with no improvement after which training will be stopped.. Defaults to 5.\n",
    "            min_delta (float, optional): Minimum change in the monitored quantity to qualify as an improvement, i.e. an absolute \n",
    "                change of less than min_delta, will count as no improvement. Defaults to 0.01.\n",
    "        \"\"\"\n",
    "        self.patience = patience\n",
    "        self.min_delta = min_delta\n",
    "        self.best_metric = -1\n",
    "        self.counter = 0\n",
    "        \n",
    "    def __call__(self, metric):\n",
    "        if metric >= self.best_metric + self.min_delta:\n",
    "            # update best metric\n",
    "            self.best_metric = metric\n",
    "            # reset counter \n",
    "            self.counter = 0\n",
    "        else: \n",
    "            self.counter += 1\n",
    "            \n",
    "    @property\n",
    "    def early_stop(self):\n",
    "        return self.counter >= self.patience\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "ExecutionIndicator": {
     "show": true
    },
    "execution": {
     "iopub.execute_input": "2025-01-22T09:37:04.052855Z",
     "iopub.status.busy": "2025-01-22T09:37:04.052684Z",
     "iopub.status.idle": "2025-01-22T09:38:20.800107Z",
     "shell.execute_reply": "2025-01-22T09:38:20.799537Z",
     "shell.execute_reply.started": "2025-01-22T09:37:04.052837Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|██████████| 7040/7040 [01:16<00:00, 91.96it/s, epoch=9] \n"
     ]
    }
   ],
   "source": [
    "# 训练\n",
    "def training(\n",
    "    model, \n",
    "    train_loader, \n",
    "    val_loader, \n",
    "    epoch, \n",
    "    loss_fct, \n",
    "    optimizer, \n",
    "    tensorboard_callback=None,\n",
    "    save_ckpt_callback=None,\n",
    "    early_stop_callback=None,\n",
    "    eval_step=500,\n",
    "    ):\n",
    "    record_dict = {\n",
    "        \"train\": [],\n",
    "        \"val\": []\n",
    "    }\n",
    "    \n",
    "    global_step = 0\n",
    "    model.train()\n",
    "    with tqdm(total=epoch * len(train_loader)) as pbar:\n",
    "        for epoch_id in range(epoch):\n",
    "            # training\n",
    "            for datas, labels in train_loader:\n",
    "                datas = datas.to(device)\n",
    "                labels = labels.to(device)\n",
    "                # 梯度清空\n",
    "                optimizer.zero_grad()\n",
    "                # 模型前向计算\n",
    "                logits = model(datas)\n",
    "                # 计算损失\n",
    "                loss = loss_fct(logits, labels)\n",
    "                # 梯度回传\n",
    "                loss.backward()\n",
    "                # 调整优化器，包括学习率的变动等\n",
    "                optimizer.step()\n",
    "                preds = logits.argmax(axis=-1)\n",
    "            \n",
    "                acc = accuracy_score(labels.cpu().numpy(), preds.cpu().numpy())    \n",
    "                loss = loss.cpu().item()\n",
    "                # record\n",
    "                \n",
    "                record_dict[\"train\"].append({\n",
    "                    \"loss\": loss, \"acc\": acc, \"step\": global_step\n",
    "                })\n",
    "                \n",
    "                # evaluating\n",
    "                if global_step % eval_step == 0:\n",
    "                    model.eval()\n",
    "                    val_loss, val_acc = evaluating(model, val_loader, loss_fct)\n",
    "                    record_dict[\"val\"].append({\n",
    "                        \"loss\": val_loss, \"acc\": val_acc, \"step\": global_step\n",
    "                    })\n",
    "                    model.train()\n",
    "                    \n",
    "                    # 1. 使用 tensorboard 可视化\n",
    "                    if tensorboard_callback is not None:\n",
    "                        tensorboard_callback(\n",
    "                            global_step, \n",
    "                            loss=loss, val_loss=val_loss,\n",
    "                            acc=acc, val_acc=val_acc,\n",
    "                            lr=optimizer.param_groups[0][\"lr\"],\n",
    "                            )\n",
    "                \n",
    "                    # 2. 保存模型权重 save model checkpoint\n",
    "                    if save_ckpt_callback is not None:\n",
    "                        save_ckpt_callback(global_step, model.state_dict(), metric=val_acc)\n",
    "\n",
    "                    # 3. 早停 Early Stop\n",
    "                    if early_stop_callback is not None:\n",
    "                        early_stop_callback(val_acc)\n",
    "                        if early_stop_callback.early_stop:\n",
    "                            print(f\"Early stop at epoch {epoch_id} / global_step {global_step}\")\n",
    "                            return record_dict\n",
    "                    \n",
    "                # udate step\n",
    "                global_step += 1\n",
    "                pbar.update(1)\n",
    "                pbar.set_postfix({\"epoch\": epoch_id})\n",
    "        \n",
    "    return record_dict\n",
    "        \n",
    "\n",
    "epoch = 10\n",
    "\n",
    "model = VGG(num_classes=10)\n",
    "\n",
    "# 1. 定义损失函数 采用交叉熵损失\n",
    "loss_fct = nn.CrossEntropyLoss()\n",
    "# 2. 定义优化器 采用 adam\n",
    "# Optimizers specified in the torch.optim package,可以修改beta1,beta2,weight_decay等参数\n",
    "optimizer = torch.optim.Adam(model.parameters(), lr=0.001,betas=(0.9,0.999))   \n",
    "    \n",
    "# 1. tensorboard 可视化\n",
    "if not os.path.exists(\"runs\"):\n",
    "    os.mkdir(\"runs\")\n",
    "tensorboard_callback = TensorBoardCallback(\"runs/vgg\")\n",
    "tensorboard_callback.draw_model(model, [1, 3, IMAGE_SIZE, IMAGE_SIZE])\n",
    "# 2. save best\n",
    "if not os.path.exists(\"checkpoints\"):\n",
    "    os.makedirs(\"checkpoints\")\n",
    "save_ckpt_callback = SaveCheckpointsCallback(\"checkpoints/vgg\", save_step=len(train_dl), save_best_only=True)\n",
    "# 3. early stop\n",
    "early_stop_callback = EarlyStopCallback(patience=5)\n",
    "\n",
    "model = model.to(device)\n",
    "record = training(\n",
    "    model, \n",
    "    train_dl, \n",
    "    eval_dl, \n",
    "    epoch, \n",
    "    loss_fct, \n",
    "    optimizer, \n",
    "    tensorboard_callback=tensorboard_callback,\n",
    "    save_ckpt_callback=save_ckpt_callback,\n",
    "    early_stop_callback=early_stop_callback,\n",
    "    eval_step=len(train_dl)\n",
    "    )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-01-22T09:39:47.252784Z",
     "iopub.status.busy": "2025-01-22T09:39:47.252426Z",
     "iopub.status.idle": "2025-01-22T09:39:47.490951Z",
     "shell.execute_reply": "2025-01-22T09:39:47.490395Z",
     "shell.execute_reply.started": "2025-01-22T09:39:47.252759Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "image/png": "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60pycrJiNBqVqVOnKlu2bOm2x167dq0CNLvMnTtXURS11eDvf/97JTY2VjGZTMrMmTOVo0ePet1HaWmpcuuttypBQUFKSEiIctdddynV1dVe2+zdu1c5//zzFZPJpAwYMEB5/vnnzyjulmIGlHfffde9TX19vfKLX/xCCQ8PVwICApTrrrtOyc/P97qfzMxMZc6cOYq/v78SFRWlPPLII4rVam12jMaPH68YjUZl4MCBXo/RUXfffbeSkpKiGI1GJTo6Wpk5c6b7pNJbY25J05NKb4z7lltuUeLj4xWj0agMGDBAueWWW7zWDOiNMbt8/fXXyujRoxWTyaQMHz5c+de//uV1e299X65YsUIBmsWiKL37eIuWybmpY+S81PPvXTk3+SZmRZHzUncca42iKErH60JCCCGEEEII0fv12zk8QgghhBBCCCEJjxBCCCGEEKLfkoRHCCGEEEII0W9JwiOEEEIIIYTotyThEUIIIYQQQvRbkvAIIYQQQggh+i1JeIQQQgghhBD9liQ8QgghhBBCiH5LEh4husidd97Jtdde29NhCCGEEICcl4RwkYRHCCGEEEII0W9JwiNEB3322WeMGTMGf39/IiMjmTVrFo8++ijvvfceX375JRqNBo1Gw7p16wDIzs7m5ptvJiwsjIiICK655hoyMzPd9+f6Bu6Pf/wj0dHRhISE8MADD2CxWHrmCQohhOhT5LwkRNv0PR2AEH1Jfn4+t956Ky+88ALXXXcd1dXV/PDDD9xxxx1kZWVRVVXFu+++C0BERARWq5XZs2czffp0fvjhB/R6PX/+85+57LLL2LdvH0ajEYDVq1fj5+fHunXryMzM5K677iIyMpJnn322J5+uEEKIXk7OS0KcniQ8QnRAfn4+NpuN66+/npSUFADGjBkDgL+/P2azmbi4OPf277//Pg6Hg0WLFqHRaAB49913CQsLY926dVx66aUAGI1G3nnnHQICAhg1ahR/+tOfePTRR/m///s/tFopxAohhGiZnJeEOD35jRWiA8aNG8fMmTMZM2YMN910E2+//Tbl5eWtbr93715OnDhBcHAwQUFBBAUFERERQUNDA+np6V73GxAQ4P55+vTp1NTUkJ2d7dPnI4QQom+T85IQpycVHiE6QKfTsWrVKjZt2sTKlSt5/fXXefLJJ9m6dWuL29fU1DBp0iQ++OCDZrdFR0f7OlwhhBD9nJyXhDg9SXiE6CCNRsN5553Heeedx9NPP01KSgpLlizBaDRit9u9tp04cSKffPIJMTExhISEtHqfe/fupb6+Hn9/fwC2bNlCUFAQSUlJPn0uQggh+j45LwnRNhnSJkQHbN26leeee44dO3aQlZXFF198QXFxMSNGjCA1NZV9+/Zx9OhRSkpKsFqt3HbbbURFRXHNNdfwww8/kJGRwbp16/jVr35FTk6O+34tFgv33HMPhw4dYtmyZTzzzDPMmzdPxkkLIYRok5yXhDg9qfAI0QEhISFs2LCBV199laqqKlJSUnj55ZeZM2cOkydPZt26dUyePJmamhrWrl3LRRddxIYNG3j88ce5/vrrqa6uZsCAAcycOdPrm7WZM2cyZMgQLrjgAsxmM7feeit/+MMfeu6JCiGE6BPkvCTE6WkURVF6OgghzmZ33nknFRUVLF26tKdDEUIIIeS8JPodqUsKIYQQQggh+i1JeIQQQgghhBD9lgxpE0IIIYQQQvRbUuERQgghhBBC9FuS8AghhBBCCCH6LUl4hBBCCCGEEP2WJDxCCCGEEEKIfksSHiGEEEIIIUS/JQmPEEIIIYQQot+ShEcIIYQQQgjRb0nCI4QQQgghhOi3JOERQgghhBBC9Fv/H9lXbaFg+4hoAAAAAElFTkSuQmCC",
      "text/plain": [
       "<Figure size 1000x500 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "#画线要注意的是损失是不一定在零到1之间的\n",
    "def plot_learning_curves(record_dict, sample_step=500):\n",
    "    # build DataFrame\n",
    "    train_df = pd.DataFrame(record_dict[\"train\"]).set_index(\"step\").iloc[::sample_step]\n",
    "    val_df = pd.DataFrame(record_dict[\"val\"]).set_index(\"step\")\n",
    "\n",
    "    # plot\n",
    "    fig_num = len(train_df.columns)\n",
    "    fig, axs = plt.subplots(1, fig_num, figsize=(5 * fig_num, 5))\n",
    "    for idx, item in enumerate(train_df.columns):    \n",
    "        axs[idx].plot(train_df.index, train_df[item], label=f\"train_{item}\")\n",
    "        axs[idx].plot(val_df.index, val_df[item], label=f\"val_{item}\")\n",
    "        axs[idx].grid()\n",
    "        axs[idx].legend()\n",
    "        # axs[idx].set_xticks(range(0, train_df.index[-1], 5000))\n",
    "        # axs[idx].set_xticklabels(map(lambda x: f\"{int(x/1000)}k\", range(0, train_df.index[-1], 5000)))\n",
    "        axs[idx].set_xlabel(\"step\")\n",
    "    \n",
    "    plt.show()\n",
    "\n",
    "plot_learning_curves(record, sample_step=100)  #横坐标是 steps"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 评估"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "ExecutionIndicator": {
     "show": true
    },
    "execution": {
     "iopub.execute_input": "2025-01-22T09:40:05.774758Z",
     "iopub.status.busy": "2025-01-22T09:40:05.774400Z",
     "iopub.status.idle": "2025-01-22T09:40:06.500752Z",
     "shell.execute_reply": "2025-01-22T09:40:06.500159Z",
     "shell.execute_reply.started": "2025-01-22T09:40:05.774734Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "loss:     0.9191\n",
      "accuracy: 0.6782\n"
     ]
    }
   ],
   "source": [
    "# dataload for evaluating\n",
    "\n",
    "# load checkpoints\n",
    "model.load_state_dict(torch.load(\"checkpoints/vgg/best.ckpt\", weights_only=True,map_location=\"cpu\"))\n",
    "\n",
    "model.eval()\n",
    "loss, acc = evaluating(model, eval_dl, loss_fct)\n",
    "print(f\"loss:     {loss:.4f}\\naccuracy: {acc:.4f}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 推理"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "ExecutionIndicator": {
     "show": false
    },
    "execution": {
     "iopub.execute_input": "2025-01-22T09:38:21.776995Z",
     "iopub.status.busy": "2025-01-22T09:38:21.776742Z",
     "iopub.status.idle": "2025-01-22T09:38:21.779724Z",
     "shell.execute_reply": "2025-01-22T09:38:21.779278Z",
     "shell.execute_reply.started": "2025-01-22T09:38:21.776973Z"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "# test_df\n",
    "# test_ds = Cifar10Dataset(\"test\", transform=transforms_eval)\n",
    "# test_dl = DataLoader(test_ds, batch_size=batch_size, shuffle=False, drop_last=False)\n",
    "\n",
    "# preds_collect = []\n",
    "# model.eval()\n",
    "# for data, fake_label in tqdm(test_dl):\n",
    "#     data = data.to(device=device)\n",
    "#     logits = model(data)\n",
    "#     preds = [test_ds.idx_to_label[idx] for idx in logits.argmax(axis=-1).cpu().tolist()]\n",
    "#     preds_collect.extend(preds)\n",
    "    \n",
    "# test_df[\"class\"] = preds_collect\n",
    "# test_df.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-01-22T09:38:21.780703Z",
     "iopub.status.busy": "2025-01-22T09:38:21.780340Z",
     "iopub.status.idle": "2025-01-22T09:38:21.782826Z",
     "shell.execute_reply": "2025-01-22T09:38:21.782322Z",
     "shell.execute_reply.started": "2025-01-22T09:38:21.780683Z"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "# 导出 submission.csv\n",
    "# test_df.to_csv(\"submission.csv\", index=False)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.14"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
